package services

import (
	"fmt"
	"sync"

	"cdk.tf/go/stack/interfaces"
	"cdk.tf/go/stack/utils"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
	"github.com/cdktf/cdktf-provider-aws-go/aws/v17/securitygroup"
)

type SecurityGroupService struct {
	securityGroups map[string]*securitygroup.SecurityGroup
	mu             sync.RWMutex
}

func NewSecurityGroupService() *SecurityGroupService {
	return &SecurityGroupService{
		securityGroups: make(map[string]*securitygroup.SecurityGroup),
	}
}

func (s *SecurityGroupService) CreateSecurityGroup(scope constructs.Construct, id string, config *interfaces.SecurityGroupConfig) (*securitygroup.SecurityGroup, error) {
	// 验证VPC ID格式
	if err := utils.ValidateVPCID(config.VpcID); err != nil {
		return nil, err
	}

	// 转换入站规则
	ingress := make([]*securitygroup.SecurityGroupIngress, len(config.IngressRules))
	for i, rule := range config.IngressRules {
		cidrBlocks := make([]*string, len(rule.CidrBlocks))
		for j, cidr := range rule.CidrBlocks {
			cidrBlocks[j] = jsii.String(cidr)
		}

		ingress[i] = &securitygroup.SecurityGroupIngress{
			Description: jsii.String(rule.Description),
			FromPort:    jsii.Number(rule.FromPort),
			ToPort:      jsii.Number(rule.ToPort),
			Protocol:    jsii.String(rule.Protocol),
			CidrBlocks:  &cidrBlocks,
		}
	}

	// 转换出站规则
	egress := make([]*securitygroup.SecurityGroupEgress, len(config.EgressRules))
	for i, rule := range config.EgressRules {
		cidrBlocks := make([]*string, len(rule.CidrBlocks))
		for j, cidr := range rule.CidrBlocks {
			cidrBlocks[j] = jsii.String(cidr)
		}

		egress[i] = &securitygroup.SecurityGroupEgress{
			Description: jsii.String(rule.Description),
			FromPort:    jsii.Number(rule.FromPort),
			ToPort:      jsii.Number(rule.ToPort),
			Protocol:    jsii.String(rule.Protocol),
			CidrBlocks:  &cidrBlocks,
		}
	}

	sgResource := securitygroup.NewSecurityGroup(scope, jsii.String(id), &securitygroup.SecurityGroupConfig{
		Name:        jsii.String(config.Name),
		Description: jsii.String(config.Description),
		VpcId:       jsii.String(config.VpcID),
		Ingress:     &ingress,
		Egress:      &egress,
		Tags:        utils.ConvertTags(config.Tags),
	})

	s.mu.Lock()
	sgID := utils.SafeDereference(sgResource.Id())
	if sgID != "" {
		s.securityGroups[sgID] = sgResource
	}
	s.mu.Unlock()

	return sgResource, nil
}

func (s *SecurityGroupService) GetSecurityGroupByID(scope constructs.Construct, sgID string) (*securitygroup.SecurityGroup, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	if sgResource, exists := s.securityGroups[sgID]; exists {
		return sgResource, nil
	}

	return nil, fmt.Errorf("Security group with ID %s not found", sgID)
}

func (s *SecurityGroupService) ListSecurityGroups() map[string]*securitygroup.SecurityGroup {
	s.mu.RLock()
	defer s.mu.RUnlock()

	result := make(map[string]*securitygroup.SecurityGroup)
	for id, sg := range s.securityGroups {
		result[id] = sg
	}
	return result
}

func (s *SecurityGroupService) GetSecurityGroupsByVPC(vpcID string) map[string]*securitygroup.SecurityGroup {
	s.mu.RLock()
	defer s.mu.RUnlock()

	result := make(map[string]*securitygroup.SecurityGroup)
	for id, sgResource := range s.securityGroups {
		if utils.SafeDereference(sgResource.VpcId()) == vpcID {
			result[id] = sgResource
		}
	}
	return result
}

func (s *SecurityGroupService) GetSecurityGroupsByName(name string) map[string]*securitygroup.SecurityGroup {
	s.mu.RLock()
	defer s.mu.RUnlock()

	result := make(map[string]*securitygroup.SecurityGroup)
	for id, sgResource := range s.securityGroups {
		if utils.SafeDereference(sgResource.Name()) == name {
			result[id] = sgResource
		}
	}
	return result
}

func (s *SecurityGroupService) GetSecurityGroupsByTags(tags map[string]string) map[string]*securitygroup.SecurityGroup {
	s.mu.RLock()
	defer s.mu.RUnlock()

	result := make(map[string]*securitygroup.SecurityGroup)
	for id, sgResource := range s.securityGroups {
		if s.securityGroupMatchesTags(sgResource, tags) {
			result[id] = sgResource
		}
	}
	return result
}

func (s *SecurityGroupService) securityGroupMatchesTags(sgResource *securitygroup.SecurityGroup, tags map[string]string) bool {
	// 简化实现
	return len(tags) == 0
}

// AddIngressRule 为现有安全组添加入站规则
func (s *SecurityGroupService) AddIngressRule(scope constructs.Construct, sgID string, rule interfaces.SecurityGroupRule) error {
	sgResource, err := s.GetSecurityGroupByID(scope, sgID)
	if err != nil {
		return err
	}

	// 创建新的安全组规则资源
	ruleName := fmt.Sprintf("%s-ingress-%d", sgID, rule.FromPort)

	cidrBlocks := make([]*string, len(rule.CidrBlocks))
	for i, cidr := range rule.CidrBlocks {
		cidrBlocks[i] = jsii.String(cidr)
	}

	securitygroup.NewSecurityGroupRule(scope, jsii.String(ruleName), &securitygroup.SecurityGroupRuleConfig{
		SecurityGroupId: sgResource.Id(),
		Type:            jsii.String("ingress"),
		Description:     jsii.String(rule.Description),
		FromPort:        jsii.Number(rule.FromPort),
		ToPort:          jsii.Number(rule.ToPort),
		Protocol:        jsii.String(rule.Protocol),
		CidrBlocks:      &cidrBlocks,
	})

	return nil
}
